package org.springframework.beans.factory.support;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.support.BeanDefinitionRegistry;
import org.springframework.beans.util.Misc;
import org.springframework.core.Resource;
import org.springframework.core.ResourceLoader;

import java.io.InputStream;

/**
 * @author xiaohei
 */
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    public XmlBeanDefinitionReader(BeanDefinitionRegistry beanDefinitionRegistry) {
        super(beanDefinitionRegistry);
    }

    public XmlBeanDefinitionReader(BeanDefinitionRegistry beanDefinitionRegistry, ResourceLoader resourceLoader) {
        super(beanDefinitionRegistry, resourceLoader);
    }

    @Override
    public void loadBeanDefinition(String location) throws BeansException {
        Resource resource = getResourceLoader().getResource(location);
        try {
            doLoadBeanDefinition(resource.getInputStream());
        } catch (Exception e) {
            throw new BeansException("load " + location + " config file failed");
        }
    }

    private void doLoadBeanDefinition(InputStream inputStream) throws Exception {
        SAXReader reader = new SAXReader();
        Document document = reader.read(inputStream);
        Element root = document.getRootElement();

        for (Element element : root.elements("bean")) {
            String id = element.attributeValue("id");
            String className = element.attributeValue("class");
            String initMethodName = element.attributeValue("init-method");
            String destroyMethodName = element.attributeValue("destroy-method");
            String scope = element.attributeValue("scope");

            BeanDefinition beanDefinition = new BeanDefinition(Class.forName(className));
            if (Misc.isNotEmpty(initMethodName)) {
                beanDefinition.setInitMethodName(initMethodName);
            }
            if (Misc.isNotEmpty(destroyMethodName)) {
                beanDefinition.setDestroyMethodName(destroyMethodName);
            }
            if (Misc.isNotEmpty(scope)) {
                beanDefinition.setScope(scope);
            }
            MutablePropertyValues propertyValues = new MutablePropertyValues();
            for (Element property : element.elements("property")) {
                String name = property.attributeValue("name");
                String value = property.attributeValue("value");
                propertyValues.addPropertyValue(new PropertyValue(name, value));
            }
            beanDefinition.setPropertyValues(propertyValues);

            getBeanDefinitionRegistry().registerBeanDefinition(id, beanDefinition);
        }
    }
}
